{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# User's Guide, Chapter 36: Clients and Weak References\n",
    "\n",
    "This chapter explains some of the underlying aspects of `music21`'s functioning that may be helpful for someone doing advanced work in understanding how the system works."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## It pays to have good references\n",
    "\n",
    "I've mentioned several times indirectly or directly the concept of references in `music21` and it's worth mentioning a bit what they are.  (Programmers with a lot of past experience outside `music21` can skim or skip ahead)\n",
    "\n",
    "A reference is a relationship between two objects that allow them to share information with each other on a short or longer term basis.  There are several types. Let me give an analogy that might help separate them.\n",
    "\n",
    "> Suppose two people (let's call them Jane and José -- the names of two students who worked on `music21`) meet at a conference mixer and discover they have a lot in common (\"You like computer music analysis too?!\"). They can chat about whatever they want at the mixer but after they leave, they have no way to communicate with each other. We'll call that being in the same scope (the mixer) but having no reference.\n",
    "\n",
    "> On the other hand, say José and Jane exchange phone numbers and emails -- now they're able to ask each other anything at any time from here on out.  I'll call this having a normal reference (also called a hard reference) to each other.\n",
    "\n",
    "> Imagine a third scenario where they exchange their hotel phone numbers (okay, unrealistic in 2015, but bear with me). Now they can chat about anything for a limited amount of time, but if Jane comes back in a month and dials room 348, odds are, she won't find José there (my travel budget isn't that big). Maybe they figure it's unlikely that they'll be in the same place again. Or sometimes it's good to have single-serving friends. In computer speak, they have weak references to each other.\n",
    "\n",
    "> It's also possible that the references can be asymmetrical. Jane could have José's permanent phone number, but José might only have Jane's room number. In this case Jane has a hard reference to José but José only has a weak reference to Jane.\n",
    "\n",
    "Most items in `music21` have no reference to each other; they can only share information when we put them in the same scope (the mixer) and introduce them to each other (e.g., statements such as `if x > y:`). \n",
    "\n",
    "On the other hand, some objects have hard references to other objects.  For instance, each `Note` object has a hard reference to a `Pitch` object. Any note can get its pitch through the `.pitch` attribute. But `Pitch` objects do not have hard references to their `Note` objects.  If you have a `Pitch` there's no `.note` attribute that lets it find its own `Note`.\n",
    "\n",
    "This seems like a design flaw, and in an ideal world, they would have references to each other. Sometimes you have a variable, such as `p`, which is a `Pitch` and it'd be great to do `p.note` to figure out what `Note` it belongs to. But there's a general rule in designing programs that's worth following: it's dangerous for two objects to have references to each other. Why? Because each object takes up space in the computer's memory. At a certain point, operating systems need to free up objects that no one is using any more (like when you close a program, all that undo data tends to vanish). Operating systems know when an object is no longer being used when there are no (hard) references to it. If `p` had a `.note` attribute pointing to `n` and `n` had a `.pitch` attribute pointing to `p` then they would never get deleted even if they were no longer in use (this process is called \"garbage collecting\").\n",
    "\n",
    "One way to get around this problem is through the use of weak references. A weak reference, like someone's room number, lets a object communicate with another for a certain length of time, but not forever. For a computer system, if `object1` has a weak reference to `object2`, it says that `object1` would like to communicate with `object2` as long as possible, but that this relationship isn't strong enough to prevent `object2` from disappearing when nothing else needs it.\n",
    "\n",
    "`Note`s and other objects have strong references to their `Duration` objects, stored in the `.duration` attribute, but `Duration` objects only have weak references to their `Note` objects. This makes sense: as long as the `Note` exists, the `Duration` had better be around, but once the `Note` disappears, there's no need to keep its `Duration`.\n",
    "\n",
    "Some objects that are in a weak reference relationship to others include `Note`s and `Stream`s. Streams have hard references to their notes -- they can't just have their notes disappearing unannounced! But Notes only have weak references to the Streams that they are in.\n",
    "\n",
    "There are many notes in a stream, but there's only one duration on a note. When there is a one-to-one relationship between two objects, the object holding the hard reference is called, in `music21`, the \"client.\" Thus in a Note/Duration relationship, the `Note` is the client of the Duration. The relationship name implies that the Duration is there to serve the client, the Note. When there's no client, the Duration is off duty and can go home.\n",
    "\n",
    "Weak references can be a bit of a pain to work with in Python compared to some other languages such as Perl (but much easier than, say, Javascript, where they are only beginning to exist). Thus `music21` as much as possible tries to hide its weak references. We hide things by making their attributes begin with an underscore `_`, which makes them not appear in the docs. For instance, if we create a `Note` and look at its `.duration.client` it looks like the Note itself:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<music21.note.Note F##>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from music21 import *\n",
    "n = note.Note(\"F##2\")\n",
    "n.duration.client"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But actually `.client` is not an attribute or reference at all, but a property: a small method that is run invisibily without needing `()` marks that converts a weakref into a normal object. The actual weakref is stored at `._client`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<weakref at 0x107967318; to 'Note' at 0x10798b630>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n.duration._client"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We have already seen the use of weak references to store clients in the Derivation method:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<music21.note.Note F##>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n.derivation.client"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n.derivation.client is n"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
